//
//  graphic.cpp
//  opengl_test
//
//  Created by 岳伸 富田 on 11/10/26.
//  Copyright (c) 2011年 __MyCompanyName__. All rights reserved.
//

#include <iostream>

#include "graphic.h"
#include "shapeshader.h"

namespace Graphic {

/**
 * Class: Core::Impl
 * Desc:
 */
class Core::Impl
{
public:
  struct Camera {
	VMA::Vector3 eye;
	VMA::Vector3 aim;
	VMA::Vector3 up;
	
	float fov;
	float nearClip;
	float farClip;	
  };
  
  struct DeviceInfo {
	int width;
	int height;
	float aspectRate;
  };
  
  Impl(){
	pShader=NULL;
	
	camera.eye=VMA::Vector3(0,5.0f,10.0f);
	camera.aim=VMA::Vector3(0,0,0);
	camera.up=VMA::Vector3(0,1.0f,0.0);
	
	camera.fov=60.0f;
	camera.nearClip=0.1f;
	camera.farClip=100.0f;
	
	view=VMA::Matrix4::lookAt(VMA::Point3(camera.eye),VMA::Point3(camera.aim),camera.up);
}
  
  void InitGL();
  void TestDraw();
  
public:
  Camera camera;
  DeviceInfo deviceInfo;
  
  VMA::Matrix4 view;
  VMA::Matrix4 proj;
  
  GLuint vboId;
  
  ShapeShader* pShader;
};    

/**
 * Name: InitGL
 * Desc:
 */
void Core::Impl::InitGL()
{
  glClearColor(0.0f,1.0f,1.0f,1.0f);
  printf("Core::Impl::InitGL\n");

  static const float vertices[] ={0.0f,1.0f,0.0f,
								  -0.5f,0.0f,0.0f,
								  0.5f,0.0f,0.0f};
  glGenBuffers(1,&vboId);
  glBindBuffer(GL_ARRAY_BUFFER,vboId);

  glBufferData(GL_ARRAY_BUFFER,sizeof(float)*9,vertices,GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER,0);

  pShader=new ShapeShader();
  pShader->Init();

  glDisable(GL_DEPTH_TEST);
}

/**
 * Name: TestDraw
 * Desc:
 */
void Core::Impl::TestDraw()
{
  pShader->Bind(0);
  
#if 0
  pShader->SetWorldMatrix(VMA::Matrix4::identity());
  pShader->SetViewMatrix(view);
  pShader->SetProjMatrix(proj);
#else
  pShader->SetWVP(proj*view);
#endif

  glBindBuffer(GL_ARRAY_BUFFER,vboId);
  
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);

  glDrawArrays(GL_TRIANGLES,0,3);
  
  glBindBuffer(GL_ARRAY_BUFFER,0);
  pShader->Unbind();
}


/**
 * Class: Core
 * Desc:
 */
    
/**
 * Name: Core
 * Desc:
 */
Core::Core()
  : m_pImpl(NULL)
{
  //
}

/**
 * Name: ~Core
 * Desc:
 */
Core::~Core()
{   
  //
}

/**
 * Name: Init
 * Desc:
 */
void Core::Init()
{
  if(m_pImpl!=NULL){
	return ;
  }
  
  m_pImpl=new Impl();
  m_pImpl->InitGL();
}


/**
 * Name: Destroy
 * Desc:
 */
void Core::Destroy()
{
  if(m_pImpl!=NULL){
	delete m_pImpl;
	m_pImpl=NULL;
  }
}

/**
 * Name: Updata
 * Desc:
 */
void Core::Update(float elapsedTime)
{
  //
}

/**
 * Name: Render
 * Desc:
 */
void Core::Render(unsigned int frame)
{
  if(m_pImpl==NULL){
	return ;
  }
  
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  m_pImpl->TestDraw();
}

/**
 * Name: Reshape
 * Desc:
 */
void Core::Reshape(int width, int height)
{
  if(m_pImpl==NULL){
	return;
  }

  m_pImpl->deviceInfo.width=width;
  m_pImpl->deviceInfo.height=height;
  if(height!=0){
	m_pImpl->deviceInfo.aspectRate=(float)width/(float)height;
  } else {
	m_pImpl->deviceInfo.aspectRate=1.0f;
  }
  
  m_pImpl->proj=VMA::Matrix4::perspective(DEGTORAD(m_pImpl->camera.fov),
										  m_pImpl->deviceInfo.aspectRate,
										  m_pImpl->camera.nearClip,
										  m_pImpl->camera.farClip);

}

/**
 * Name: GetViewMatrix
 * Desc:
 */
const VMA::Matrix4& Core::GetViewMatrix()
{
  return m_pImpl->view;
}

/**
 * Name: GetProjMatrix
 * Desc:
 */
const VMA::Matrix4& Core::GetProjMatrix()
{
  return m_pImpl->proj;
}



} // namespace Graphic
